<template>
  <div
    ref="PieGraph"
    :id="id"
    :style="{ height: pieStyle.height, width: width }"
  ></div>
</template>

<script lang="ts">
import { Vue, Component, Prop, Watch } from "vue-property-decorator";
import * as echarts from "echarts";

// echarts 调色盘
const Palette = [
  "#2A8EFF",
  "#FFB300",
  "#2740DB",
  "#00FF82",
  "#5ADCFC",
  "#B437E8",
  "#E8598F",
  "#BA4833"
];

const pieStyle = {
  height: "165px",
  graphicImgWidth: 80,
  graphicImgHeight: 80,
  graphicTextTop: "33%",
  graphicTextFontSize: 16,
  graphicNameTop: "43%",
  seriesCenterY: "37%",
  seriesRadiusIn: "30%",
  seriesRadiusOut: "38%",
  seriesLableShowNum: true
};

type DataType = {
  name: string;
  value: string | number;
};

@Component({
  name: "PieGraph"
})
export default class extends Vue {
  @Prop({ default: null }) id?: string;
  @Prop({ default: "100%" }) width?: string;
  @Prop({ default: "0" }) right?: string;
  @Prop({ default: () => [] }) dataset!: any;
  @Prop({ default: () => Palette }) color?: any;
  @Prop({ default: "" }) totalName?: string;
  @Prop({ default: () => pieStyle }) pieStyle?: any;
  /**
   * 饼状图中心指定图形元素类型 image || text
   * text 则显示合计总数
   * image 则中心显示图片, 同时需要传入 graphicImage
   */
  @Prop({ default: "text" }) graphicType?: string;
  /**
   * graphicImage 传入图片及尺寸
   * {
   *    image: String,
   *    width: Number,
   *    height: Number,
   *    top: String
   * }
   */
  @Prop({ default: null }) graphicImage?: any;
  @Prop({ default: false }) showTotal?: boolean;
  @Prop({ default: false }) showPercentage?: boolean;

  total: number = 0;
  chart: any = null;
  radiusInner: any = require("@/assets/images/panels/bingtubeijing.png");

  @Watch("dataset", { immediate: false, deep: true })
  handleData(newVal: any) {
    newVal && this.init();
  }

  mounted() {
    this.init();
  }

  /**
   * methods
   */
  init() {
    this.total = 0;
    this.chart && this.chart.dispose();

    for (const item of this.dataset) {
      const { value } = item;
      if (!isNaN(Math.abs(Number(value)))) {
        this.total += Math.abs(Number(value));
      }
    }
    // 增加百分比
    let index = 0;
    const percentages = [];
    for (const item of this.dataset) {
      const { value } = item;
      let percentage =
        Number(value) === 0
          ? value
          : new Number((Number(value) / this.total) * 100).toFixed(0);

      if (index + 1 === this.dataset.length) {
        const sum = percentages.reduce((a, b) => this.add(a, b));
        percentage = this.sub(100, sum);

        item.percentage = percentage;
        percentages.push(percentage);
      } else {
        item.percentage = percentage;
        percentages.push(percentage);
      }

      index++;
    }

    const dom = this.$refs["PieGraph"] as HTMLDivElement;
    this.chart = echarts.init(dom);
    this.chart.setOption(this.updateOptions(), true);
  }
  updateOptions() {
    const {
      graphicImgWidth,
      graphicImgHeight,
      graphicNameTop,
      seriesCenterY,
      seriesRadiusIn,
      seriesRadiusOut,
      seriesLableShowNum
    } = this.pieStyle;

    const graphicItem = this.setGraphicItem();
    console.log("graphicItem", graphicItem);

    const seriesLable =
      seriesLableShowNum === false ? "{a|{b}}" : "{a|{b}}\n{c|{c}}\n";

    const rich = this.setLegendRich();

    const defaultOptions = {
      color: this.color,
      grid: {},
      graphic: [
        {
          type: "image",
          top: "center",
          style: {
            image: this.radiusInner,
            width: graphicImgWidth || pieStyle.graphicImgWidth,
            height: graphicImgHeight || pieStyle.graphicImgHeight,
            x: parseInt(this.pieStyle.height) / 20 + 35
          }
        },
        graphicItem
        // {
        //   type: "text",
        //   top: "center",
        //   left: "center",
        //   style: {
        //     text: this.totalName, // 环内第二行文字设置
        //     textAlign: "center",
        //     fill: "#9297B6", // 文字的颜色
        //     width: 30,
        //     height: 20,
        //     fontSize: 10,
        //     lineHeight: "14",
        //     color: "#FFFFFF",
        //     // x: parseInt(this.pieStyle.height) / 2,
        //   },
        // },
      ],
      series: [
        {
          name: "",
          type: "pie",
          radius: [
            seriesRadiusIn || pieStyle.seriesRadiusIn,
            seriesRadiusOut || pieStyle.seriesRadiusOut
          ],
          center: ["42%", "50%"],
          label: {
            show: true,
            position: "outer",
            alignTo: "edge",
            margin: 10,
            lineHeight: 15,
            formatter: "{b}\n{d}%",
            color: "#fff"
          },
          labelLine: {
            length: 15,
            length2: 0
          },
          labelLayout: function(params: any) {
            const isLeft = params.labelRect.x < 94;
            const points = params.labelLinePoints;
            points[2][0] = isLeft
              ? params.labelRect.x
              : params.labelRect.x + params.labelRect.width;
            return {
              labelLinePoints: points
            };
          },
          itemStyle: {
            borderColor: "#001022",
            borderWidth: 1
          },
          data: this.dataset,
          width: this.width,
          height: this.pieStyle.height
        }
      ]
    };

    return defaultOptions;
  }

  setLegendRich() {
    if (this.showPercentage) {
      return {
        a: {
          width: 35,
          fontSize: 13,
          color: "rgba(255,255,255,.85)",
          padding: [0, 5, 0, 4]
        },
        c: {
          width: 50,
          color: "#FFFFFF",
          align: "center",
          fontSize: 15,
          padding: [0, 4, 0, 4]
        },
        d: {
          width: 40,
          color: "#FFFFFF",
          align: "right",
          fontSize: 15,
          padding: [0, 4, 0, 4]
        }
      };
    }

    return {
      a: {
        width: 40,
        fontSize: 14,
        color: "rgba(255,255,255,.85)"
      },
      c: {
        width: 60,
        color: "#FFFFFF",
        align: "left",
        fontSize: 16
      }
    };
  }

  setGraphicItem() {
    const { graphicTextTop, graphicTextFontSize } = this.pieStyle;

    if (this.graphicType === "text" && this.showTotal) {
      return {
        type: "text",
        top: "center",
        style: {
          text: this.total + "户", // 环内第二行文字设置
          textAlign: "center",
          fill: "#FFFFFF", // 文字的颜色
          width: 30,
          height: 20,
          fontSize: graphicTextFontSize || pieStyle.graphicTextFontSize,
          lineHeight: "24",
          color: "#FFFFFF",
          x: parseInt(this.pieStyle.height) / 2 
        }
      };
    }

    if (this.graphicType === "image" && this.graphicImage) {
      const { image, width, height, top } = this.graphicImage;
      return {
        type: "image",
        left: "center",
        top: top || pieStyle.graphicTextTop,
        style: {
          image: image,
          width: width,
          height: height,
          x: parseInt(this.pieStyle.height) / 4
        }
      };
    }

    return {
      type: "text",
      left: "center"
    };
  }

  getValueByName(name: string) {
    let value = "0";
    if (!name) {
      return value;
    }

    for (const item of this.dataset) {
      if (item.name === name) {
        value = item.value + "";
      }
    }

    return value;
  }

  getPercenttageByName(name: string) {
    let value = "0";
    if (!name) {
      return value;
    }

    for (const item of this.dataset) {
      if (item.name === name) {
        value = Number(item.percentage) === 0 ? value : item.percentage + "%";
      }
    }

    return value;
  }

  /**
   ** 加法函数，用来得到精确的加法结果
   ** 说明：javascript的加法结果会有误差，在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。
   ** 调用：accAdd(arg1,arg2)
   ** 返回值：arg1加上arg2的精确结果
   **/
  add(arg1: number, arg2: number) {
    let r1, r2, m, c;
    try {
      r1 = arg1.toString().split(".")[1].length;
    } catch (e) {
      r1 = 0;
    }
    try {
      r2 = arg2.toString().split(".")[1].length;
    } catch (e) {
      r2 = 0;
    }
    c = Math.abs(r1 - r2);
    m = Math.pow(10, Math.max(r1, r2));
    if (c > 0) {
      var cm = Math.pow(10, c);
      if (r1 > r2) {
        arg1 = Number(arg1.toString().replace(".", ""));
        arg2 = Number(arg2.toString().replace(".", "")) * cm;
      } else {
        arg1 = Number(arg1.toString().replace(".", "")) * cm;
        arg2 = Number(arg2.toString().replace(".", ""));
      }
    } else {
      arg1 = Number(arg1.toString().replace(".", ""));
      arg2 = Number(arg2.toString().replace(".", ""));
    }

    return (arg1 + arg2) / m;
  }

  /**
   ** 减法函数，用来得到精确的减法结果
   ** 说明：javascript的减法结果会有误差，在两个浮点数相减的时候会比较明显。这个函数返回较为精确的减法结果。
   ** 调用：accSub(arg1,arg2)
   ** 返回值：arg1加上arg2的精确结果
   **/
  sub(arg1: any, arg2: any) {
    let r1, r2, m, n;
    try {
      r1 = arg1.toString().split(".")[1].length;
    } catch (e) {
      r1 = 0;
    }
    try {
      r2 = arg2.toString().split(".")[1].length;
    } catch (e) {
      r2 = 0;
    }
    m = Math.pow(10, Math.max(r1, r2)); //last modify by deeka //动态控制精度长度
    n = r1 >= r2 ? r1 : r2;
    return ((arg1 * m - arg2 * m) / m).toFixed(n);
  }
}
</script>

<style lang="scss" scoped></style>
